{% extends "base.html" %}
{% comment 'header' %}
# This file is part of opentaps Smart Energy Applications Suite (SEAS).

# opentaps Smart Energy Applications Suite (SEAS) is free software:
# you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# opentaps Smart Energy Applications Suite (SEAS) is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public License
# along with opentaps Smart Energy Applications Suite (SEAS).
# If not, see <https://www.gnu.org/licenses/>.
{% endcomment %}

{% load static i18n %}
{% load bootstrap4 %}
{% block title %}Topics{% endblock %}

{% block content %}

  {% include "core/_breadcrumbs.html" %}
  {% load render_table from django_tables2 %}
  {% url 'core:topic_import' as topic_import_url %}
  {% url 'core:tag_import' as tag_import_url %}
  {% url 'core:topic_export0' as topic_export_url %}
  {% url 'core:topic_report_tags_csv' as topic_report_tags_url %}
  {% url 'core:topictagruleset_list' as topictagruleset_list %}

  {% if crate_conn %}
  <div class="card mb-3">
    <div class="card-body p-2 p-md-3" id="topics-list" v-cloak>
        <div class="alert alert-success alert-dismissible fade show mt-3" role="alert" v-if="create_rule_success">
          <div>Successfully ${ create_rule_success.action } Rule "${ create_rule_success.rule.name }" in Rule Set "${ create_rule_success.rule_set.name }" ${ create_rule_success.details }.</div>
          <button type="button" class="close" aria-label="Close" v-on:click="create_rule_success = false">
            <span aria-hidden="true">&times;</span>
          </button>
        </div>
        <form action="" method="get" class="form" ref="topics_filter_form" v-on:submit.prevent="noop">
            <div class="filters">
              <div class="m-0 mb-2 mr-2 p-0 col-auto text-right flex-grow-1 d-flex flex-column flex-sm-row justify-content-end">
                <div class="btn-group">
                <button type="button" class="btn btn-primary mb-2 mb-sm-0 mr-sm-2 dropdown-toggle" data-toggle="dropdown">
                  <i class="fa fa-upload"></i> Import
                </button>
                <div class="dropdown-menu">
                  <a class="dropdown-item" href="{{ tag_import_url }}">from CSV</a>
                  <a class="dropdown-item" href="{{ topic_import_url }}">from VOLTTRON BACNet Scans</a>
                </div>
                </div>

                {% bootstrap_button '<i class="fa fa-robot"></i> Rules' button_class='btn-primary mb-2 mb-sm-0 mr-sm-2' href=topictagruleset_list %}

                <div class="btn-group">
                <button type="button" class="btn btn-primary mb-2 mb-sm-0 mr-sm-2 dropdown-toggle" data-toggle="dropdown">
                  <i class="fa fa-download"></i> Export
                </button>
                <div class="dropdown-menu">
                  <a class="dropdown-item" href="{{ topic_report_tags_url }}">to CSV</a>
                  <a class="dropdown-item" href="{{ topic_export_url }}">to VOLTTRON Configs</a>
                </div>
                </div>
              </div>

              <div class="row m-0" v-for="(filter, index) in filters">
                <div class="row p-0 m-0 mb-2 col-12">
                  <div class="mr-2 p-0 col-auto" style="min-width:4.5em">
                    <div v-if="index">
                      <select class="form-control" v-model="filter.op" v-on:change="changed_filter_type(filter, index)">
                        <option value="AND">AND</option>
                        <option value="OR">OR</option>
                      </select>
                    </div>
                  </div>
                  <div class="mr-2 p-0 col-auto" style="min-width:7em">
                    <v-select select-on-tab :options="filter_fields" v-model="filter.field" placeholder="Field" :clearable="false" class="opt_w_auto">
                      <template slot="option" slot-scope="option">
                        ${ option.label }&nbsp;<small>${ option.description }</small>
                      </template>
                      <template slot="selected-option" slot-scope="option">
                        ${ option.label }
                      </template>
                    </v-select>
                  </div>
                  <div class="mr-2 p-0 col-auto">
                    <select class="form-control" v-model="filter.type" v-on:change="changed_filter_type(filter, index)">
                      <option value="c">Contains</option>
                      <option value="nc">Not Contains</option>
                      <option value="eq">Equals</option>
                      <option value="neq">Not Equals</option>
                      <option value="gt">></option>
                      <option value="gte">>=</option>
                      <option value="lt"><</option>
                      <option value="lte"><=</option>
                      <option value="present">Is Present</option>
                      <option value="absent">Is Absent</option>
                      <option value="matches">Matches</option>
                    </select>
                  </div>
                  <div class="mr-2 p-0 col flex-grow">
                    <input type="text" class="form-control" placeholder="Filter ..." v-model="filter.value" v-on:keyup="filter_on_enter" v-if="is_value_required(filter)">
                  </div>
                  <div class="mr-2 p-0 col-auto">
                    <div v-if="index == filters.length - 1">
                      <a href="#" class="btn btn-outline-secondary" v-on:click="add_filter(filter)"><i class="fa fa-filter"></i></a>
                    </div>
                    <div v-else>
                      <a href="#" class="btn btn-outline-danger" v-on:click="delete_filter(filter, index)"><i class="fa fa-minus"></i></a>
                    </div>
                  </div>
                </div>

              </div>
              <input type="hidden" name="filters_count" value="{{ used_filters|length }}" />
            </div>

            <div class="rounded-lg bg-light mb-2 row">
              <div class="col-xl-4 col-lg-4">
                <input id="select_not_mapped_topics" type="checkbox" v-model="select_not_mapped_topics" v-on:change="submit_filters" class="invisible position-absolute"/>
                <label class="m-0 w-100 mx-auto text-center pt-2 pb-2 text-primary h-c" for="select_not_mapped_topics">
                  <span v-if="!select_not_mapped_topics" class="light-btn">Show unmapped topics only.</span>
                  <span v-if="select_not_mapped_topics" class="light-btn">Show all topics.</span>
                </label>
              </div>
              <div class="col-xl-4 col-lg-4" v-if="!select_not_mapped_topics">
                <input id="his_tagged_topics_only" type="checkbox" v-on:change="add_his_to_filter" class="invisible position-absolute"/>
                <label class="m-0 w-100 mx-auto text-center pt-2 pb-2 text-primary h-c" for="his_tagged_topics_only">
                  <span class="light-btn">Show his tagged topics only.</span>
                </label>
              </div>
              <div :class="[topics_counter ? 'col-xl-3' : 'col-xl-4', topics_counter ? 'col-lg-3' : 'col-lg-4']">
                 <b-form-group style="margin-bottom: 0px;" label-cols-sm="5" label-cols="7" label-cols-lg="7" label-cols-xl="8" label-align-sm="left" label-align-lg="right" label="View" label-for="per_page">
                   <select name="per_page" id="per_page" class="form-control page-length" v-model="per_page">
                      <option value="10">10</option>
                      <option value="25">25</option>
                      <option value="50">50</option>
                      <option value="100">100</option>
                      <option value="250">250</option>
                    </select>
                  </b-form-group>
              </div>

              <div class="col-xl-1 col-lg-1" v-if="topics_counter" style="padding-left:0px;padding-top:8px;">
                <div class="text-sm-center text-lg-left text-xl-left">of ${ topics_counter }</div>
              </div>

              <div class="col-xl-6 col-lg-8" v-if="all_selected || select_all_matching">
                <input id="select_all_matching" type="checkbox" name="_ALL_" class="invisible position-absolute" v-model="select_all_matching" />
                <label class="m-0 w-100 mx-auto text-center pt-2 pb-2 h-c" for="select_all_matching">
                  <span v-if="!select_all_matching" class="text-primary light-btn">Select all that match the filters on all pages.</span>
                  <span v-if="select_all_matching" class="text-secondary">All topics on all pages selected.</span>
                  <span v-if="select_all_matching" class="text-primary light-btn">Clear selection.</span>
                </label>
              </div>
            </div>

        </form>
        <div class="alert alert-danger mt-3" role="alert" v-if="topic_table_errors.error">
            ${ topic_table_errors.error }
        </div>
        <b-table striped hover
            class="topics-table"
            :items="load_topics_page"
            :fields="topic_fields"
            :per-page="per_page"
            :current-page="page"
            id="topics-table"
            ref="topics_table"
            :sort-by.sync="sortBy"
            :sort-desc.sync="sortDesc"
            sort-icon-left
            no-local-sorting>

            <template v-slot:table-busy>
              <div class="text-center filter-spiner-placeholder my-2">
                <b-spinner label="Loading..." variant="secondary"></b-spinner>
              </div>
            </template>

            <template v-slot:head(actions)="data">
              <input type="checkbox" @click.stop="toggle_selected" v-model="all_selected" :disabled="select_all_matching">
            </template>

            <template v-slot:head(view)="data">
              <b-btn variant="light" size="sm" @click.stop="edit_topic_fields()"><i class="fa fa-cog"></i></b-btn>
            </template>

            <template v-slot:cell(actions)="item">
              <input type="checkbox" name="checked" :key="item.index" :value="item.item" @click.stop v-model="checked_items" :disabled="select_all_matching">
            </template>

            <template v-slot:cell(view)="item">
              <a v-if="item.item.point" class="btn btn-secondary btn-sm" :href="get_point_link(item.item)"><i class="fa fa-external-link-alt"></i>  View</a>
              <a v-if="!item.item.point" class="btn btn-secondary btn-sm" :href="get_add_point_link(item.item)"><i class="fa fa-plus"></i>  Add</a>
            </template>
        </b-table>

        <b-pagination
          v-model="page"
          :total-rows="total_rows"
          :per-page="per_page"
          :limit="7"
          aria-controls="topics-table"
          align="center"
        ></b-pagination>

        <div id="topic-fields-form-modal" :csrfmiddlewaretoken="csrfmiddlewaretoken"></div>
    </div>
  </div>

  <div id="topic-tag-form" v-cloak>

    <div class="card mb-3">
      <div class="card-body">
        <h4 class="position-relative">Tag Selected Topics <div class="a-rt">
          <button class="btn btn-secondary mr-2" style="top:-0.5em" :disabled="isSaving" v-on:click.stop.prevent="save_tags_from_model()"><i class="fa fa-plus mr-2"></i> Add From Model</button>
          <button class="btn btn-secondary" style="top:-0.5em" :disabled="isSaving" v-on:click.stop.prevent="save_remove()"><i class="fa fa-minus mr-2"></i> Remove Tag</button>
          <button class="btn btn-secondary" style="top:-0.5em" :disabled="isSaving" v-on:click.stop.prevent="save_add()"><i class="fa fa-plus mr-2"></i> Add Tag</button>
        </div></h4>
        <!--Add Tag-->
        <form novalidate v-if="isInitial || isSaving" class="main-form">
          <div class="container p-0" v-if="isAddingModel">
            <div class="alert alert-danger mt-3" role="alert" v-if="errors.error">
                ${ errors.error }
              </div>
              <div class="alert alert-success alert-dismissible fade show mt-3" role="alert" v-if="tag_topics_success">
                <div style="max-height:15em;overflow:auto">
                  Added the tags:
                  <ul>
                    <li v-for="tag in tag_topics_success.tags">
                      ${ display_tag(tag) }
                    </li>
                  </ul>

                  <div v-if="tag_topics_success.updated">to ${ tag_topics_success.updated } topics/data points</div>

                </div>
                <button type="button" class="close" aria-label="Close">
                  <span aria-hidden="true" v-on:click="tag_topics_success = false">&times;</span>
                </button>
            </div>
            <div class="form-group">
              <h5>Select Model</h5>
              <div v-for="item in model_selects" v-bind:key="item.level">
                <v-select v-if="item.models" :get-option-label="get_model_label" select-on-tab :options="item.models" v-model="item.model" @input="item.select_model" class="mb-2" placeholder="Select a Model ...">
                  <template slot="option" slot-scope="option">
                    ${ option.object_id }&nbsp;<small>${ option.description }</small>
                  </template>
                  <template slot="selected-option" slot-scope="option">
                    ${ option.object_id }&nbsp;<small>${ option.description }</small>
                  </template>
                </v-select>
              </div>
            </div>
            <div v-if="last_model_selected">
              <ul>
                <li v-for="tag in get_model_kvtags(last_model_selected)">${ tag.tag }: ${ tag.value }</li>
                <li v-for="tag in get_model_mtags(last_model_selected)">${ tag.tag }</li>
              </ul>
            </div>
            <div ref="add_tags_from_model_btn">
              <button v-if="last_model_selected" class="btn btn-outline-secondary" :disabled="isSaving" v-on:click.stop.prevent="save_tags_from_model()"><i class="fa fa-plus mr-2"></i> Add these Tags</button>
            </div>
          </div>
          <div class="container p-0" v-if="isAddingTag">
            <div class="col">
              <div class="alert alert-danger mt-3" role="alert" v-if="errors.error">
                ${ errors.error }
              </div>
              <div class="alert alert-success alert-dismissible fade show mt-3" role="alert" v-if="tag_topics_success">
                <div style="max-height:15em;overflow:auto">
                  Added the tags:
                  <ul>
                    <li v-for="tag in tag_topics_success.tags">
                      ${ display_tag(tag) }
                    </li>
                  </ul>

                  <div v-if="tag_topics_success.updated">to ${ tag_topics_success.updated } topics/data points</div>

                </div>
                <button type="button" class="close" aria-label="Close">
                  <span aria-hidden="true" v-on:click="tag_topics_success = false">&times;</span>
                </button>
              </div>
              <div class="form-group">
                <label for="tagInput">${ isAddingTagToRemove ? 'Remove' : 'Add' } Tag</label>
                <vue-bootstrap-typeahead
                  input-class="form-control"
                  :serializer="s => s.tag + ': ' + s.description"
                  id="tagInput"
                  ref="tagInput"
                  name="tag" v-model="tag"
                  @hit="selectedTag = $event"
                  :data="valid_tags" placeholder="Tag...">
                  <template slot="suggestion" slot-scope="{ data, htmlText }">
                    <span v-html="htmlText"></span>&nbsp;<small>${ data.kind }</small>
                  </template>
                </vue-bootstrap-typeahead>
                <span v-for="err in errors.tag" class="text-danger">${ err }</span>
              </div>

              <tag-value-input
                v-if="!isAddingTagToRemove"
                :csrfmiddlewaretoken="csrfmiddlewaretoken"
                :selected-tag="selectedTag"
                v-model="value"
                :errors="errors.value"></tag-value-input>

              <button class="invisible a-rt" :disabled="isSaving" v-on:click.stop.prevent="save()">Save</button>
            </div>
          </div>
        </form>
        <!--List Tags-->
        <div class="container tags-table ftable" ref="tag_list">
          <div scope="row" v-for="(item, idx) in sorted_items" :class="{ 'even': idx % 2 === 0, 'odd': idx % 2 !== 0, 'row': 1, 'align-items-start': 1, 'justify-content-between': 1, 'ftable-row': 1 }" v-if="should_display_tag(item)">
            <div :class="[item._protect ? 'col-12' : 'col-8', 'col-lg-auto', 'text-nowrap', 'm-0']">
              <i class="fa fa-minus" v-if="item.remove && item.remove === true || item.remove == 'True'"></i>
              <i class="fa fa-plus" v-else></i>
              <span v-if="!get_link(item)">${display_tag(item)}</span>
              <a v-if="get_link(item)" :href="get_link(item)">${display_tag(item)}</a>
              <div v-if="item.parent_id" class="text-muted text-small text-wrap">
                from <a :href="model_link(item)" target="_blank">${model_link_text(item)}</a>
              </div>
            </div>
            <div v-if="!item._protect" class="buttons text-nowrap col-auto row">
              <button v-if="item.value" v-on:click="edit_tag(idx)" class="btn btn-outline-primary btn-sm mr-1"><i class="fas fa-edit"></i></button>
              <button v-confirm="set_confirm(idx)" class="btn btn-outline-danger btn-sm"><i class="fas fa-trash"></i></button>
            </div>
          </div>
        </div>

        <!--modal-->
        <tag-form-modal
          title="Edit Tag"
          url=""
          :csrfmiddlewaretoken="csrfmiddlewaretoken"></tag-form-modal>

        <div class="form-group d-flex justify-content-around" v-if="sorted_items.length">
          <button class="btn btn-primary col-5" :disabled="isSaving" v-on:click.stop.prevent="apply_tags()"><i v-if="isSaving" class="fas fa-spinner fa-spin"></i><i v-else class="fa fa-check mr-2"></i> Apply Tags</button>
          <button v-if="!editing_rule" class="btn btn-secondary col-5" :disabled="isSaving" v-on:click.stop.prevent="toggle_show_save_rule()">Save as a Rule <i class="fa fa-chevron-right ml-2"></i></button>
        </div>
      </div>
    </div>

    <div class="card mb-3" v-if="show_save_rule">
      <div class="card-body">
        <h4 class="position-relative">Rule Action : Create Equipment
          <div class="a-rt">
            <button v-if="!rule_action_edit" class="btn btn-secondary" style="top:-0.5em" v-on:click.stop.prevent="edit_rule_action()">Edit</button>
            <button v-if="!rule_action_edit && rule_action" class="btn btn-danger" style="top:-0.5em" v-confirm:click.stop.prevent="delete_rule_action()"><i class="fa fa-trash mr-2"></i> Delete</button>
          </div>
        </h4>
        <div v-if="!rule_action_edit && rule_action">
          <div>Site: ${rule_action_fields.site_object_id}</div>
          <div>Equipment Name: ${rule_action_fields.equipment_name}</div>
          <div>Model: ${rule_action_fields.model_object_id}</div>
        </div>

        <div v-if="rule_action_edit">
          <div class="form-group">
            <label for="siteObjectId">Site*</label>
            <select name="siteObjectId" class="select form-control" id="siteObjectId" v-model="rule_action_edit_fields.site_object_id">
                {% for c in sites_list %}
                    <option value="{{ c.id }}">{{ c.description }}</option>
                {% endfor %}
            </select>
          </div>
          <div class="form-group">
            <label for="equipmentName">Equipment Name*</label>
            <b-form-input type="text" class="form-control" id="equipmentName" placeholder="Equipment Name" :state="equipmentNameState" v-model="rule_action_edit_fields.equipment_name" required></b-form-input>
            <b-form-invalid-feedback id="equipmentName">
                Equipment Name is required
            </b-form-invalid-feedback>
          </div>
          <div class="form-group">
            <label for="modelObjectId">Model</label>
            <v-select select-on-tab :options="rule_action_models.models"
                      label="description" :reduce="description => description.object_id"  id="modelObjectId" v-model="rule_action_edit_fields.model_object_id" class="mb-2" placeholder="Select a Model ...">
              <template slot="option" slot-scope="option">
                ${ option.object_id }&nbsp;<small>${ option.description }</small>
              </template>
              <template slot="selected-option" slot-scope="option">
                ${ option.object_id }&nbsp;<small>${ option.description }</small>
              </template>
            </v-select>

          </div>
          <div class="form-group d-flex justify-content-around">
            <button type="button" class="btn btn-secondary" v-on:click.stop.prevent="cancel_edit_rule_action()"><i class="fa fa-times mr-2"></i> Cancel</button>
            <button type="button" class="btn btn-primary" v-on:click.stop.prevent="save_edit_rule_action()"><i class="fa fa-check mr-2"></i> Save</button>
          </div>
        </div>
       </div>
    </div>

    <div class="card mb-3" v-if="show_save_rule">
      <div class="card-body">
        <h4 ref="save_rule_title">Save as a Rule</h4>
        <div class="alert alert-danger mt-3" role="alert" v-if="rule_errors.error">
          ${ rule_errors.error }
        </div>
        <div class="alert alert-success alert-dismissible fade show mt-3" role="alert" v-if="create_rule_success">
          <div>Successfully ${ create_rule_success.action } Rule "${ create_rule_success.rule.name }" in Rule Set "${ create_rule_success.rule_set.name }" ${ create_rule_success.details }.</div>
          <button type="button" class="close" aria-label="Close" v-on:click="create_rule_success = false">
            <span aria-hidden="true">&times;</span>
          </button>
        </div>
        <form action="" method="get" class="form" ref="save_as_rule_form" v-on:submit.prevent="set_save_rule">
          <div class="form-group">
            <label for="ruleSet">Rule Set</label>
            <div class="row">
              <div class="col col-auto">
                <select class="form-control" v-model="ruleset_type">
                  <option v-if="editing_rule" value="current">Current: {{ rule.rule_set.name|safe }}</option>
                  <option value="new">Create New</option>
                  <option value="existing">Select Existing</option>
                </select>
              </div>
              <div class="col">
                <input type="text" class="form-control" id="ruleSet" placeholder="Rule Set" v-model="ruleset_name" v-if="ruleset_type == 'new'" required />

              <vue-bootstrap-typeahead
                required
                v-if="ruleset_type == 'existing'"
                :input-class="'form-control' + (rule_errors['rule_set_id'] ? ' is-invalid' : '')"
                :serializer="s => s.name"
                :min-matching-chars="0"
                name="selected_ruleset"
                @hit="selected_ruleset = $event"
                v-model="ruleset_id"
                :data="valid_rulesets"
                placeholder="Choose a rule set">
                <template slot="suggestion" slot-scope="{ data, htmlText }">
                  <span v-html="htmlText"></span>&nbsp;<small>${ data.name || data.id }</small>
                </template>
              </vue-bootstrap-typeahead>
              </div>
            </div>
          </div>
          <div class="form-group">
            <label for="ruleName">Rule Name</label>
            <input type="text" class="form-control" id="ruleName" placeholder="Rule Name" v-model="rulename" required />
          </div>
          <div class="form-group d-flex justify-content-around">
            <button v-if="editing_rule" type="button" class="btn btn-primary" v-on:click.stop.prevent="update_rule()"><i class="fa fa-check mr-2"></i> Update Rule</button>
            <button v-if="editing_rule" type="submit" class="btn btn-primary"><i class="fa fa-check mr-2"></i> Save as a New Rule</button>
            <button v-if="!editing_rule" type="submit" class="btn btn-primary"><i class="fa fa-check mr-2"></i> Save as a Rule</button>
          </div>
        </form>
      </div>
    </div>

  </div>
  {% else %}
    <div class="card mb-3"><div class="card-body">Crate database unavailable.</div></div>
  {% endif %}

{{ rule.tags|json_script:'rule_tags' }}
<script>
(function() {
  {% if rule %}const RULE_TAGS = JSON.parse(document.getElementById('rule_tags').textContent);{% endif %}
  {% load js_csrf_token from core_tags %}
  const CSRF_TOKEN = '{% js_csrf_token %}';

  Vue.component('tag-form-modal', {
    delimiters: ['$[', ']'],
    extends: Vue.component('form-modal'),
    data() {
      return {
        fields: [
          { key: 'value', value: '', type: 'tag', selectedTag: null },
        ]
      }
    },
    created: function () {
      eventHub.$on('showModal_tag', this.showModal)
    },
    methods:{
      post_show: function(item){
        console.log('post_show', item)
        this.fields[0].selectedTag = item
        this.fields[0].value = item.value ? item.value : ''
      },
      save: function() {
        item.value = this.fields[0].value
        this.closeModal()
      }
    }
  });
  new Vue({
    delimiters: ['${', '}'],
    el: '#topic-tag-form',
    name: 'topic-tag-form',
    extends: Vue.component('base-list-form'),
    data() {
      return {
        csrfmiddlewaretoken: CSRF_TOKEN,
        selectedTag: {},
        selected_ruleset: {},
        valid_tags: [],
        model_selects: [],
        last_model_selected: false,
        rule_errors: {},
        tag: '',
        value: '',
        rule_action: {%if rule %}'{{ rule_action|safe}}'{%else%}''{%endif%},
        rule_action_fields: {%if rule_action_fields %}{{ rule_action_fields|safe}}{%else%}{}{%endif%},
        rule_action_edit: false,
        rule_action_edit_fields: {},
        rule_action_models: [],
        rule_action_delete: false,
        default_rule_action_site_id: {%if default_rule_action_site_id %}'{{ default_rule_action_site_id|safe}}'{%else%}''{%endif%},
        equipmentNameState: null,
        isAddingTag: false,
        isAddingModel: false,
        isAddingTagToRemove: false,
        tag_topics_success: false,
        create_rule_success: false,
        editing_rule: {% if rule %}true{%else%}false{%endif%},
        show_save_rule: {% if rule %}true{%else%}false{%endif%},
        valid_rulesets: [],
        ruleset_type: {%if rule %}'current'{%else%}'new'{%endif%},
        ruleset_name: '',
        ruleset_id: {%if rule %}'{{ rule.rule_set.id|safe}}'{%else%}''{%endif%},
        rulename: {%if rule %}'{{ rule.name|safe}}'{%else%}''{%endif%},
        {% if rule %}items: RULE_TAGS,{% endif %}
      }
    },
    created: function () {
      axios.get('{% url 'core:tag_list_json' %}')
        .then(x => this.valid_tags = x.data.items)
        .catch(err => {
          console.error('loading tags error :', err);
        });
      eventHub.$on('tag_topics_success', this.show_tag_topics_success)
      eventHub.$on('apply_rule', this.apply_rule)
      eventHub.$on('applying_tags', this.set_status)
      eventHub.$on('applying_tags_error', this.set_error)
      eventHub.$on('tag_changed', x => {
        if (x.item.tag == 'modelRef') wait().then(this.reloadTags())
      })
    },
    mounted() {
      this.get_valid_rulesets()
      this.load_models(this.rule_action_models, false, true)
    },
    computed: {
      sorted_items() {
        return this.items.sort((a,b) => {
          if (a.value && !b.value) return -1
          if (!a.value && b.value) return 1
          return a.tag.localeCompare(b.tag)
        })
      },
    },
    watch: {
      selectedTag: function (val) {
        if (val.kind == 'Marker' || this.isAddingTagToRemove) {
          this.save()
        }
      },
    },
    methods:{
      reset() {
        // call base reset
        this._reset()
        this.selectedTag = {}
        this.tag_topics_success = false
        this.create_rule_success = false
        this.rule_errors = {}
        this.tag = ''
        this.value = ''
        if (this.$refs.tagInput) this.$refs.tagInput.inputValue = ''
        this.last_model_selected = false
        this.model_selects = [{
          level: 0,
          select_model: this.select_model_cb(0),
          models: [],
          model: ''
        }]
        this.load_models(this.model_selects[0])
      },
      reset_all() {
        this.reset()
        this.selected_ruleset = {}
        this.editing_rule = false
        this.isAddingTag = false
        this.isAddingModel = false
        this.isAddingTagToRemove = false
        this.show_save_rule = false
        this.ruleset_type = 'new'
        this.ruleset_name = ''
        this.ruleset_id = ''
        this.rulename = ''
        this.items = []
      },
      toggle_show_save_rule() {
        this.show_save_rule = !this.show_save_rule
        if (this.show_save_rule) {
          this.$nextTick(() => this.$refs.save_rule_title.scrollIntoView())
        }
      },
      edit_rule_action() {
          this.rule_action_edit = true;
          this.rule_action_edit_fields = Object.assign({}, this.rule_action_fields);
          if (!this.rule_action_edit_fields.site_object_id && this.default_rule_action_site_id) {
              this.rule_action_edit_fields.site_object_id = this.default_rule_action_site_id;
          }
      },
      cancel_edit_rule_action() {
          this.rule_action_edit = false;
          this.rule_action_edit_fields = {}
      },
      save_edit_rule_action() {
          if (this.rule_action_edit_fields.equipment_name) {
              this.rule_action_edit = false;
              this.rule_action_fields = Object.assign({}, this.rule_action_edit_fields);
              this.rule_action = 'create equipment';
              this.rule_action_delete = false;
              this.equipmentNameState = null;
          } else {
              this.equipmentNameState = false;
          }
      },
      delete_rule_action() {
          return {
            okText: 'Delete',
            ok: dialog => this.delete_rule_action_cb(dialog),
            message: 'Are you sure?'
          }
      },
      delete_rule_action_cb(dialog) {
          this.rule_action_fields = {};
          this.rule_action = '';
          this.rule_action_edit = false;
          this.rule_action_delete = true;
          dialog.close()
      },
      set_status(saving) {
        this.currentStatus = saving ? STATUS_SAVING : STATUS_INITIAL
      },
      set_error(e) {
        this.errors = e
      },
      apply_rule(rule) {
        if (rule.tags) this.items = rule.tags
      },
      get_point_link(item) {
        return dutils.urls.resolve('point_detail', { id: item.point })
      },
      display_point(item) {
        return item.name || item.point
      },
      show_tag_topics_success(res) {
        this.tag_topics_success = res
      },
      should_display_tag(tag) {
        // do not display a tag that was inherited if another same tag overrides it
        if (!tag._protect) return true;
        var i = this.items.find(x => !x._protect && x.tag == tag.tag);
        return (!i);
      },
      model_link(item) {
        return dutils.urls.resolve('model_detail', { id: item.parent_id })
      },
      model_link_text(item) {
        if (!item || !item.parent_description) return ''
        return item.parent_description
      },
      get_link(tag) {
        return dutils.urls.resolve_tag_linked_value(tag)
      },
      edit_tag(idx) {
        item = this.items[idx]
        eventHub.$emit('showModal_tag', item)
      },
      tag_needs_value(item) {
        return (!this.isAddingTagToRemove && item && item.kind && item.kind != 'Marker')
      },
      display_tag(item) {
        if (item.value) {
          return (item.tag) + ': ' + item.value
        } else {
          return '✓ ' + (item.tag)
        }
      },
      display_tag_short(item) {
        if (item.value) {
          return (item.tag) + ': ' + item.value
        } else {
          return '✓ ' + (item.tag)
        }
      },
      delete_item(item, idx) {
        console.log('delete_item', item, idx)
        this.$delete(this.items, idx)
        return Promise.resolve()
      },
      scroll_add_from_model(i) {
        if (i && this.$refs.add_tags_from_model_btn) {
          this.$refs.add_tags_from_model_btn.scrollIntoView()
        } else {
          setTimeout(()=>{
            this.$nextTick(() => this.scroll_add_from_model(1))
          },100)
        }
      },
      add_tag_if_not_in_items(tag, model) {
        if (!this.items) this.items = []
        var found = false
        for (var i=0; i<this.items.length; i++) {
          var t = this.items[i]
          if (t.tag == tag.tag) {
            found = t
            break
          }
        }
        if (found) {
          found.value = tag.value
          if (model) {
            found.parent_id = model.entity_id
            found.parent_description = model.description
          }
        } else {
          if (model) {
            tag.parent_id = model.entity_id
            tag.parent_description = model.description
          }
          this.items.push(tag)
        }
      },
      save_tags_from_model() {
        this.scroll_add_from_model()
        if (!this.isAddingModel) {
          this.isAddingTag = false
          this.isAddingModel = true
          return
        }
        if (!this.last_model_selected) return
        tags = this.get_model_kvtags(this.last_model_selected).concat(this.get_model_mtags(this.last_model_selected))
        console.log('** save_tags_from_model', tags)
        for (var i=0; i<tags.length; i++) {
          console.log('** save_tags_from_model add tag', tags[i])
          this.add_tag_if_not_in_items(tags[i], this.last_model_selected)
        }
      },
      scroll_add_tag(i) {
        if (i && this.$refs.tag_list) {
          this.$refs.tag_list.scrollIntoView()
        } else {
          setTimeout(()=>{
            this.$nextTick(() => this.scroll_add_tag(1))
          },100)
        }
      },
      save_remove() {
        this.isAddingTagToRemove = true
        this.save()
      },
      save_add() {
        this.isAddingTagToRemove = false
        this.save()
      },
      save() {
        this.scroll_add_tag()
        if (!this.isAddingTag) {
          this.isAddingTag = true
          this.isAddingModel = false
          return
        }
        var i = this.items.find(x => !x._protect && x.tag == (this.selectedTag ? this.selectedTag.tag : this.tag));
        if (i) {
          this.errors = getResponseError('This Tag is already set ' + (i.description || i.tag) + (i.value ? ': ' + i.value : ''))
          return
        }

        t = this.selectedTag ? this.selectedTag.tag : this.tag
        v = null
        var need_val = this.tag_needs_value(this.selectedTag)
        var has_val = this.value && this.value.length
        if (need_val) {
          if (has_val) {
            v = this.value
          } else {
            this.errors = getResponseError({error: 'This Tag requires a value', value: ['A value is required']})
            return
          }
        }
        _tag = {tag: t, value: v, remove: this.isAddingTagToRemove}
        if (this.selectedTag) {
          _tag.kind = this.selectedTag.kind
          _tag.description = this.selectedTag.description
        }
        if (_tag.tag) {
          console.log('*** add tag', _tag, this.selectedTag)
          this.items.push(_tag)
          this.reset()
        }
      },
      apply_tags() {
        console.log('*** apply tags', this.items)
        this.errors = {}
        eventHub.$emit('apply_tags', this.items)
      },
      get_model_mtags(model) {
        if (!model || !model.m_tags) return []
        var tags = []
        for (var i=0; i<model.m_tags.length; i++) {
          var key = model.m_tags[i]
          if (key == 'model') continue
          tags.push({tag: key})
        }
        return tags
      },
      get_model_kvtags(model) {
        if (!model || !model.kv_tags) return []
        var tags = []
        for (var key in model.kv_tags) {
          // remove tags we do not want to list
          if (key == 'id') continue
          if (key == 'dis') continue
          if (key == 'modelRef') continue
          if (model.kv_tags.hasOwnProperty(key)) {
            tags.push({tag: key, value: model.kv_tags[key]})
          }
        }
        return tags
      },
      select_model_cb(idx) {
        return x => {
          console.log('*** selected_model for', idx, x)
          // incase of deselect x will be null
          if (x) {
            this.last_model_selected = x
            level = idx+1
          } else {
            if (idx>0) {
              this.last_model_selected = this.model_selects[idx-1].model
            } else {
              this.last_model_selected = false
            }
            level = idx
          }
          if (this.model_selects.length > level) {
            this.model_selects.splice(level)
          }
          this.model_selects.push({
            level: level,
            select_model: this.select_model_cb(level),
            models: null,
            parent: x,
            model: ''
            })
          this.load_models(this.model_selects[this.model_selects.length-1], true)
        }
      },
      get_model_label(model) {
        return model.object_id + ' ' + model.description
      },
      load_models(model_select, scroll, all) {
        console.log('** load_models for =', model_select)
        parent = '_'
        if (model_select.parent && model_select.parent.object_id) {
          parent = model_select.parent.object_id
        }
        url = dutils.urls.resolve('model_list_json') + '?parent=' + parent
        if (all) {
            url = dutils.urls.resolve('model_list_json')
        }
        axios.get(url)
          .then(x => {
            console.log('load_models', x.data.items)
            if (x.data.items && x.data.items.length) model_select.models = x.data.items
              if (scroll) this.scroll_add_from_model()
          })
          .catch(err => {
            console.error('loading models error :', err);
          });
      },
      get_valid_rulesets(site) {
        url = dutils.urls.resolve('topic_rules')
        axios.get(url)
          .then(x => {
            console.log('get_valid_rulesets', x.data.rules)
            this.valid_rulesets = x.data.rules
          })
          .catch(err => {
            console.error('loading valid_rulesets error :', err);
          });
      },
      update_rule() {
        console.log('Update rule !')
        if (this.editing_rule) {
          this.set_save_rule({
            rule_id: '{{ rule.id }}',
            rule_set_id: '{{ rule.rule_set.id }}'
          })
        }
      },
      is_value_required(filter) {
        return !(filter.type == 'absent' || filter.type == 'present')
      },
      set_save_rule(update_data) {
        // check there are filters or tags to save
        filters = eventHub.get_filters()
        select_not_mapped_topics = eventHub.get_select_not_mapped_topics()
        valid_filters = []
        tags = this.items
        this.create_rule_success = false
        console.log('*** ruleset_type =', this.ruleset_type)
        console.log('*** ruleset_name =', this.ruleset_name)
        console.log('*** rulename =', this.rulename)
        console.log('*** tags =', tags)
        console.log('*** filters =', filters)
        console.log('*** select_not_mapped_topics =', select_not_mapped_topics)
        // build text of selected filters and tags:
        details = ''
        for (var i=0; i<filters.length; i++) {
          // check at least one has value
          f = filters[i]
          if (!this.is_value_required(f) || f.value) {
            console.log('*** filter = ', f)
            var field = f.field ? (f.field.value || f.field) : 'topic'
            valid_filters.push({
              field: field,
              type: f.type,
              op: f.op,
              value: f.value
            })
            if (field != 'topic' && field != 'Topic') {
              details += ' ' + field
            }
            if (f.type == 'c') {
              details += ' contains'
            } else if (f.type == 'nc') {
              details += ' does not contain'
            } else if (f.type == 'present') {
              details += ' is present, '
            } else if (f.type == 'absent') {
              details += ' is absent, '
            }
            if (this.is_value_required(f)) {
              details += ' "' + f.value + '", '
            }
          }
        }
        if (valid_filters.length) {
          details = 'for topics that ' + details
        } else {
          details = 'for *ALL* topics ' + details
        }
        console.log('*** valid_filters =', valid_filters)
        if (tags.length) {
          var apply_tags_list = []
          var remove_tags_list = []

          for (var i=0; i<tags.length; i++) {
            tag = tags[i]
            if (tag.remove && tag.remove === true || tag.remove == "True") {
              remove_tags_list.push(tag)
            } else {
              apply_tags_list.push(tag)
            }
          }

          if (apply_tags_list.length) {
            details += ' apply the tags: '
            for (var i=0; i<apply_tags_list.length; i++) {
              if (i>0) details += ', '
              tag = apply_tags_list[i]
              details += tag.tag
              if (tag.value) details += '=' + tag.value
            }
          }

          if (remove_tags_list.length) {
            details += ' remove the tags: '
            for (var i=0; i<remove_tags_list.length; i++) {
              if (i>0) details += ', '
              tag = remove_tags_list[i]
              details += tag.tag
            }
          }
        }

        if (!valid_filters.length || !tags.length) {
          if (!this.rule_action_delete) {
              if (!this.rule_action || (this.rule_action && !this.rule_action.length)) {
                  return this.rule_errors = {error: 'No filters, actions or tags to save.'}
              }
          }
        }

        // Save it:
        this.rule_errors = {}
        url = dutils.urls.resolve('topic_rules')
        data = {name: this.rulename, tags: tags, filters: valid_filters}
        if (update_data) {
          if (update_data.rule_id) {
            data.rule_id = update_data.rule_id
          }
          if (update_data.rule_set_id) {
            data.rule_set_id = update_data.rule_set_id
          }
        }
        if ('new' == this.ruleset_type) {
          data.rule_set_id = 'new'
          data.rule_set_name = this.ruleset_name
        } else if ('existing' == this.ruleset_type) {
          if (this.selected_ruleset) {
            if (this.selected_ruleset.rule_set_id) {
              data.rule_set_id = this.selected_ruleset.rule_set_id
            } else {
              data.rule_set_name = this.selected_ruleset.name
            }
          } else {
            data.rule_set_name = this.ruleset_name
          }
        } else if ('current' == this.ruleset_type) {
              data.rule_set_id = this.ruleset_id
        }
        if (this.rule_action && this.rule_action.length) {
            data.rule_action = this.rule_action;
            if (this.rule_action_fields) {
                data.rule_action_fields = this.rule_action_fields;
            }
        } else if (this.rule_action_delete) {
            data.rule_action_delete = this.rule_action_delete
        }
        console.log('saving rule', data);
        axios.post(url, data, {headers: {'X-CSRFToken': this.csrfmiddlewaretoken}})
          .then(x => x.data)
          .then(x => {
            if (x.success) {
              console.log('saved rule, rules = ', x)
              success_msg = {
                action: (x.success == 'updated') ? 'updated' : 'created',
                details: details,
                rule: x.rule,
                rule_set: x.rule_set
              }
              {% if not rule %}
              console.log('Rule saved. Reseting the form and sending success message:', success_msg)
              eventHub.$emit('saved_rule', success_msg)
              this.reset_all()
              {% else %}
              console.log('Rule saved, setting success message:', success_msg)
              if (success_msg.action == 'updated') {
                this.create_rule_success = success_msg
              } else {
                eventHub.$emit('saved_rule', success_msg)
                this.reset_all()
              }
              {% endif %}
            } else {
              return Promise.reject(x.errors)
            }
          })
          .catch(err => {
            e = getResponseError(err)
            console.error(e, err)
            this.rule_errors = e
          });
      }
    }
  });
  new Vue({
    delimiters: ['${', '}'],
    el: '#topics-list',
    name: 'topics-list',
    data() {
      return {
        csrfmiddlewaretoken: CSRF_TOKEN,
        page: 1,
        filter_fields: [
          { label: 'Topic', value: 'topic' },
          { label: 'bacnet_objectName', value: 'bacnet_objectName' },
          { label: 'bacnet_bacnet_object_type', value: 'bacnet_bacnet_object_type' },
          { label: 'bacnet_device_name', value: 'bacnet_device_name' },
          { label: 'bacnet_device_id', value: 'bacnet_device_id' },
          { label: 'bacnet_units', value: 'bacnet_units' },
          { label: 'ID', value: 'id' }
        ],
        filters: [
          {% for f in used_filters %}
            {
              field: '{{f.field|default:"Topic"}}',
              type: '{{f.type|default:"c"}}',
              op: '{{f.op|default:"AND"}}',
              value: '{{f.value}}'
            },
          {% endfor %}
        ],
        topic_fields: [],
        default_topic_fields: [
          {
            key: 'actions',
            label: '',
            'class': 'text-left'
          },
          {
            key: 'topic',
            sortable: true
          },
          {
            key: 'bacnet_objectName',
            label: 'Object Name',
            sortable: true
          },
          {
            key: 'bacnet_presentValue',
            label: 'Present Value',
            sortable: true,
          },
          {
            key: 'bacnet_units',
            label: 'Units',
            sortable: true,
          },
          {
            key: 'view',
            label: '',
            'class': 'text-right'
          },
        ],
        topic_items: [],
        create_rule_success: false,
        selected_topics: {},
        select_not_mapped_topics: false,
        all_checked: false,
        select_all_matching: false,
        show_load_data_spinner: false,
        per_page: 10,
        total_rows: 0,
        topics_counter: null,
        checked_items: [],
        all_selected: false,
        sortBy: 'topic',
        sortDesc: false,
        topic_table_errors: {}
      }
    },
    mounted: function () {
        this.read_page_number(window.location.href)
    },
    created: function () {
      axios.get('{% url 'core:tag_list_json' %}')
        .then(x => x.data.items)
        .then(x => {
          for (var i=0;i<x.length;i++) {
            this.filter_fields.push({
              label: x[i].tag,
              description: x[i].description,
              value: x[i].tag
            })
          }
        })
        .catch(err => {
          console.error('loading tags error :', err);
        });
      eventHub.$on('apply_tags', this.apply_tags)
      eventHub.$on('saved_rule', this.saved_rule)
      eventHub.get_filters = () => {
        return this.filters
      }
      eventHub.get_select_not_mapped_topics = () => {
        return this.select_not_mapped_topics
      }
      eventHub.$on('apply_topicFields', this.apply_topic_fields)
    },
    watch: {
    },
    methods: {
      noop() {
        console.log('noop __')
      },
      saved_rule(msg) {
        console.log('** saved rule', msg)
        this.create_rule_success = msg
        this.$el.scrollIntoView()
      },
      apply_rule(rule) {
        console.log('** apply rule', rule)
        if (rule.filters) {
          this.filters = rule.filters
          this.submit_filters()
        }
        eventHub.$emit('apply_rule', rule)
      },
      filter_on_enter(e) {
        if (e.keyCode === 13) {
            this.submit_filters()
        }
      },
      is_value_required(filter) {
        return !(filter.type == 'absent' || filter.type == 'present')
      },
      changed_filter_type(filter, index) {
        console.log('changed_filter_type', filter)
        if ((!this.is_value_required(filter) || filter.value) && index < this.filters.length-1) {
            this.$refs.topics_table.refresh();
        }
      },
      delete_filter(filter, index) {
        console.log('delete_filter', filter)
        this.filters.splice(index, 1)
        this.submit_filters()
      },
      append_blank_filter() {
        this.filters.push({field: 'Topic', type: 'c', value: '', op: 'AND'})
      },
      check_add_blank_filter() {
        f = this.filters[this.filters.length-1]
        console.log('check_add_blank_filter last filter', f, this.filters)
        if (!this.is_value_required(f) || (f.value && f.value.trim().length)) this.append_blank_filter()
      },
      add_filter(filter) {
        console.log('add_filter', filter)
        if (!this.is_value_required(filter) ||(filter.value)) {
            this.append_blank_filter()
            this.submit_filters()
        }
      },
      build_filter_data(formData) {
        n = 0
        for (var i=0; i<this.filters.length; i++) {
            var f = this.filters[i]
            var field = f.field ? (f.field.value || f.field) : 'topic'
            if (!this.is_value_required(f) || f.value) {
                formData.set('n'+n, field)
                formData.set('t'+n, f.type)
                formData.set('f'+n, f.value)
                formData.set('o'+n, f.op)
                n++
            }
        }
        formData.set('filters_count', n)
        console.log('build_filter_data select_not_mapped_topics = ', this.select_not_mapped_topics)
        if (this.select_not_mapped_topics) {
          formData.set('select_not_mapped_topics', 1)
        }
      },
      submit_filters(event) {
        console.log('submit_filters...', event)
        this.check_add_blank_filter()
        this.$refs.topics_table.refresh();
        if (event) {
            event.preventDefault()
            return false
        }
      },
      add_his_to_filter(event) {
          this.filters.unshift({field: 'his', type: 'present', value: '', op: 'AND'});
          this.$refs.topics_table.refresh();
      },
      read_page_number(href) {
        if (href) {
            g = href.match('\\?.+$')
            if (!g) {
              this.page = 1
              return
            }
            params = g[0]
            g = params.match('page=(\\d+)')
            this.page = g ? g[1] : 1
            console.log('read_page_number [' + this.page + '] from params', params)
        }
      },
      get_point_link(item) {
        return dutils.urls.resolve('point_detail', { id: item.point })
      },
      get_add_point_link(item) {
        return dutils.urls.resolve('topic_setup', { id: item.topic })
      },
      edit_topic_fields() {
        eventHub.$emit('showModal_topicFields', this.topic_fields, this.default_topic_fields)
      },
      apply_topic_fields(new_fields) {
          console.log('apply_topic_fields: ', new_fields)
          this.topic_fields = new_fields
          this.sortBy = 'topic'
          this.sortDesc = false
          // save fields
          url = dutils.urls.resolve('topic_table_fields')

          axios.post(url, new_fields, {headers: {'X-CSRFToken': this.csrfmiddlewaretoken}})
            .then(x => x.data)
            .then(x => {
              if (x.success) {
                console.log('apply_topic_fields: successfully saved')
                // re load page
                this.$refs.topics_table.refresh();
              } else {
                return Promise.reject(x.errors)
              }
            })
            .catch(err => {
              console.error('apply_topic_fields: save topic table fields error', err)
            });

      },
      toggle_selected() {
          this.all_selected = !this.all_selected;
          this.reset_checked_items(this.all_selected)
      },
      reset_checked_items(all_selected) {
          if (all_selected) {
              this.checked_items = []
              for(var i=0; i<this.topic_items.length; i++) {
                  this.checked_items.push(this.topic_items[i])
              }
          } else {
              this.checked_items = []
          }
      },
      load_topics_page(ctx) {
          console.log('load_topics_page, ctx: ', ctx)
          this.topic_table_errors = {}
          url = dutils.urls.resolve('topic_json')
          const formData = new FormData()
          this.build_filter_data(formData)
          formData.set('csrfmiddlewaretoken', this.csrfmiddlewaretoken)
          if (ctx) {
              if (ctx.sortBy) {
                  formData.set('sortBy', ctx.sortBy)
                  if (ctx.sortDesc) {
                      formData.set('sortDesc', 'Y')
                  }
              }
          }
          this.topic_items = []
          _this = this
          let promise = axios.post(url + '?page=' + this.page +'&per_page=' + this.per_page, formData)

          return promise.then(response => {
              var cn = parseInt(response.data.count)
              this.total_rows = cn
              if (cn > 0 && this.filters.length > 1 && cn > this.per_page) {
                  this.topics_counter = response.data.count
              } else {
                  this.topics_counter = null
              }
              this.show_load_data_spinner = false;

              console.log("load_topics_page: data", response.data)
              var data_items = response.data.data
              var error = response.data.error
              if (error) {
                  this.topic_table_errors['error'] = error
              } else {
                  if (!this.topic_fields || (this.topic_fields && !this.topic_fields.length)) {
                      if (response.data.topic_fields) {
                          this.topic_fields = response.data.topic_fields
                      } else {
                          this.topic_fields = this.default_topic_fields
                      }
                  }
                  console.log('load_topics_page: topic_fields', this.topic_fields)

                  if (data_items && data_items.length) {
                      for (var i=0; i<data_items.length; i++) {
                          var item = {topic: data_items[i].topic}
                          if (data_items[i].m_tags && data_items[i].m_tags.includes('point')) {
                              if (data_items[i].point_entity_id) {
                                  item['point'] = data_items[i].point_entity_id
                              }
                          }
                          if (data_items[i].kv_tags) {
                              for (var j=1; j<this.topic_fields.length-1; j++) {
                                  tag_value = data_items[i].kv_tags[this.topic_fields[j].key]
                                  if (tag_value) {
                                      item[this.topic_fields[j].key] = tag_value
                                  }
                              }
                          }
                          if (data_items[i].m_tags) {
                              for (var j=1; j<this.topic_fields.length-1; j++) {
                                  if (data_items[i].m_tags.includes(this.topic_fields[j].key)) {
                                      item[this.topic_fields[j].key] = 'X';
                                  }
                              }
                          }
                          console.log('row:', item)
                          this.topic_items.push(item)
                      }
                  }
                  if (this.select_all_matching) {
                      this.reset_checked_items(this.all_selected)
                  } else {
                      this.all_selected = false
                      this.checked_items = []
                  }
              }
              return this.topic_items;
          }).catch(error => {
              console.log('load_topics_page: error =', error)
              this.all_selected = false
              this.select_all_matching = false
              this.checked_items = []
              return this.topic_items;
          });
      },
      apply_tags(items) {
        console.log('apply_tags tag = ', items)
        console.log('apply_tags to topics = ', this.selected_topics)
        // post as JSON
        tags = []
        for (var i=0; i<items.length; i++) {
          tags.push({tag: items[i].tag, value: items[i].value, remove: items[i].remove})
        }
        topics = []
        for (var i=0; i<this.checked_items.length; i++) {
            topics.push(this.checked_items[i].topic)
        }

        filters = []
        for (var i=0; i<this.filters.length; i++) {
          var f = this.filters[i]
          console.log('apply_tags filter ? ', f)
          if ((f.value && f.value.length) || !this.is_value_required(f)) {
            var field = f.field ? (f.field.value || f.field) : 'topic'
            filters.push({
              n: field,
              t: f.type,
              o: f.op,
              f: f.value
            })
          }
        }
        data = {tags: tags, topics: topics, filters: filters, select_all: this.select_all_matching}
        if (this.select_not_mapped_topics) {
          data.select_not_mapped_topics = 1
        }
        console.log('apply_tags JSON = ', data)
        if (tags.length) {
          eventHub.$emit('applying_tags', true)
          url = dutils.urls.resolve('tag_topics')
          axios.post(url, data, {headers: {'X-CSRFToken': this.csrfmiddlewaretoken}})
            // get data
            .then(x => x.data)
            .then(x => {
              if (x.success) {
                this.post_save(x)
                eventHub.$emit('applying_tags', false)
                return x
              } else {
                return Promise.reject(x.errors)
              }
            })
            .catch(err => {
              eventHub.$emit('applying_tags', false)
              e = getResponseError(err)
              console.error(e, err)
              eventHub.$emit('applying_tags_error', e)
            });
        }
      },
      post_save(x) {
        console.log('updated topics tags', x.updated)
        eventHub.$emit('tag_topics_success', x)
      }
    }
  });

  new Vue({
    delimiters: ['$[', ']'],
    el: '#topic-fields-form-modal',
    name : 'topic-fields-form-modal',
    template: `
    <transition name="modal" v-if="visible">
      <div class="form-modal modal-mask">
        <div class="modal-wrapper">
          <div class="modal-container">

            <div class="modal-header" >
                Topic Fields List
                <button v-on:click="resetToDefault()" class="btn btn-outline-danger"> Reset To Default</button>
            </div>

            <div class="modal-body">

                <b-table :items="edit_fields" :fields="fields">
                    <template v-slot:cell(action)="item">
                      <button v-on:click="deleteRow(item.index)" class="btn btn-outline-danger btn-sm  ml-1"><i class="fas fa-trash"></i></button>
                    </template>

                    <template v-slot:cell(label)="item">
                        <b-form-input type="text" v-model="item.item.label"></b-form-input>
                    </template>
                </b-table>

                <div class="row p-0 m-0 mb-2 col-12">
                <div class="mr-2 p-0 col flex-grow" style="min-width:7em">
                  <v-select select-on-tab :options="tags" v-model="current_tag" placeholder="Field" :clearable="false" class="opt_w_auto">
                    <template slot="option" slot-scope="option">
                      $[ option.label ]&nbsp;<small>$[ option.description ] $[ option.kind ]</small>
                    </template>
                    <template slot="selected-option" slot-scope="option">
                      $[ option.label ]
                    </template>
                  </v-select>
                </div>
                <div class="mr-2 p-0 col-auto">
                    <button v-on:click="addField()" class="btn btn-outline-primary">Add</i></button>
                </div>
                </div>

            </div>

            <div class="modal-footer">
              <button class="modal-default-button btn btn-outline-danger" @click="closeModal">Cancel</button>
              <button class="modal-default-button btn btn-outline-primary" @click="save">Save</button>
            </div>
          </div>
        </div>
      </div>
    </transition>
    `,
    props: {
      csrfmiddlewaretoken: String
    },
    data() {
      return {
        errors: {},
        visible: false,
        topic_fields: [],
        edit_fields: [],
        default_topic_fields: [],
        fields: [
          {
            key: 'key',
          },
          {
            key: 'label',
          },
          {
            key: 'action',
            label: '',
            'class': 'text-right'
          },
        ],
        tags: [],
        current_tag: null
      }
    },
    created: function () {
      eventHub.$on('showModal_topicFields', this.showModal)
    },
    methods:{
      showModal: function(topic_fields, default_topic_fields){
        console.log('showModal', topic_fields, default_topic_fields)
        this.tags = []
        this.current_tag = null
        this.visible = true
        this.errors = {}
        this.edit_fields = []
        this.topic_fields = topic_fields
        this.default_topic_fields = default_topic_fields
        if (topic_fields.length > 3) {
            for (var i=2; i<(topic_fields.length-1); i++) {
                this.edit_fields.push({key: topic_fields[i].key, label: topic_fields[i].label, sortable: topic_fields[i].sortable})
            }
        }

        axios.get('{% url 'core:tag_list_json' %}')
          .then(x => x.data.items)
          .then(x => {
            for (var i=0;i<x.length;i++) {
              this.tags.push({
                label: x[i].tag,
                description: x[i].description,
                value: x[i].tag,
                kind: x[i].kind
              })
            }
          })
          .catch(err => {
            console.error('loading tags error :', err);
          });
      },
      closeModal: function(){
        this.visible = false
        this.errors = {}
      },
      deleteRow: function(index) {
        console.log('deleteRow', index)
        this.edit_fields.splice(index, 1)
      },
      addField: function() {
        console.log('addField', this.current_tag)
        if (this.current_tag) {
            this.edit_fields.push({key: this.current_tag.value, label: this.current_tag.description, kind: this.current_tag.kind})
        }
      },
      resetToDefault: function() {
          this.edit_fields = []
          if (this.default_topic_fields.length > 3) {
              for (var i=2; i<(this.default_topic_fields.length-1); i++) {
                  this.edit_fields.push({key: this.default_topic_fields[i].key, label: this.default_topic_fields[i].label, sortable: this.default_topic_fields[i].sortable})
              }
          }
      },
      save: function() {
        console.log('save', this.edit_fields)
        var new_fields = []
        new_fields.push(this.topic_fields[0])
        this.topic_fields[1]['sortable'] = true
        new_fields.push(this.topic_fields[1])

        if (this.edit_fields.length) {
            for (var i=0; i<this.edit_fields.length; i++) {
                if (this.edit_fields[i].hasOwnProperty('kind')) {
                    if (this.edit_fields[i]['kind'] == 'Marker') {
                        this.edit_fields[i]['sortable'] = false
                    } else {
                        this.edit_fields[i]['sortable'] = true
                    }
                }
                new_fields.push(this.edit_fields[i])
            }
        }

        new_fields.push(this.topic_fields[this.topic_fields.length-1])
        eventHub.$emit('apply_topicFields', new_fields)
        this.closeModal()
      }
    }
  });
})();
</script>
{% endblock content %}
